#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"

using namespace cocos2d;
using namespace CocosDenshion;

CCScene* HelloWorld::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    
    // 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }
    
    /////////////////////////////
    // 2. add a menu item
    /////////////////////////////
    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                                          "CloseNormal.png",
                                                          "CloseSelected.png",
                                                          this,
                                                          menu_selector(HelloWorld::menuCloseCallback) );
    pCloseItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20) );
    // create menu, it's an autorelease object
    CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
    //pMenu->setVisible(false);
    pMenu->setPosition( CCPointZero );
    this->addChild(pMenu, 1);

    //加入星星
    this->addChild(CCParticleSystemQuad::particleWithFile("Stars1.plist")) ;
    this->addChild(CCParticleSystemQuad::particleWithFile("Stars2.plist")) ;
    this->addChild(CCParticleSystemQuad::particleWithFile("Stars3.plist")) ;
    
    //批量加入图片
    _batchNode = CCSpriteBatchNode::create("Sprites.pvr.ccz");
    this->addChild(_batchNode);
    
    CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("Sprites.plist");
    
    _ship = CCSprite::spriteWithSpriteFrameName("SpaceFlier_sm_1.png");
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    _ship->setPosition(ccp(winSize.width*.1, winSize.height*.5));
    _batchNode->addChild(_ship,1);
    
    _backgroundNode = CCParallaxNodeExtras::node();
    this->addChild(_backgroundNode, -1);
    
    _spacedust1 = CCSprite::create("bg_front_spacedust.png");
    _spacedust2 = CCSprite::create("bg_front_spacedust.png");
    _planetsunrise = CCSprite::create("bg_planetsunrise.png");
    _galaxy = CCSprite::create("bg_galaxy.png");
    _spacialanomaly = CCSprite::create("bg_spacialanomaly.png");
    _spacialanomaly2 = CCSprite::create("bg_spacialanomaly2.png");
    
    CCPoint dustSpeed = ccp(0.1,0.1);
    CCPoint bgSpeed = ccp(.05,.05);
    
    _backgroundNode->addChild(_spacedust1, 0, dustSpeed, ccp(0,winSize.height/2));
    _backgroundNode->addChild(_spacedust2, 0, dustSpeed, ccp(_spacedust1->getContentSize().width, winSize.height/2));
    _backgroundNode->addChild(_galaxy, -1, bgSpeed, ccp(0, winSize.height*.7));
    _backgroundNode->addChild(_planetsunrise,-1,bgSpeed, ccp(600,winSize.height*0));
    _backgroundNode->addChild(_spacialanomaly, -1, bgSpeed, ccp(900,winSize.height*.3));
    _backgroundNode->addChild(_spacialanomaly2, -1, bgSpeed, ccp(1500,winSize.height*.9));
    

    
    // 控制一屏能出现的陨石量
    #define KNUMASTEROIDS 15
    _asteroids = new CCArray;
    for (int ii=0; ii<KNUMASTEROIDS; ii++)
    {
        CCSprite *asteroid = CCSprite::spriteWithSpriteFrameName("asteroid.png");
        asteroid->setVisible(false);
        _batchNode->addChild(asteroid);
        _asteroids->addObject(asteroid);
    }
   
    #define KNUMLASERS 5
    _shipLasers = new CCArray;
    for (int ii=0; ii<KNUMLASERS; ii++)
    {
        CCSprite *shipLaser = CCSprite::spriteWithSpriteFrameName("laserbeam_blue.png");
        shipLaser->setVisible(false);
        _batchNode->addChild(shipLaser);
        _shipLasers->addObject(shipLaser);
    }
    
    //打开平衡感应
    this->setAccelerometerEnabled(true);
    this->setTouchEnabled(true);

    //场景动作
    this->scheduleUpdate();
    
    //初始化输赢处理
    _lives = 3 ;
    double curTime = getTimeTick() ;
    _gameOverTime = curTime + 30000 ;
    
    //声音处理
    SimpleAudioEngine::sharedEngine()->playBackgroundMusic("SpaceGame.wav",true) ;
    SimpleAudioEngine::sharedEngine()->preloadEffect("explosion_large.wav") ;
    SimpleAudioEngine::sharedEngine()->preloadEffect("laser_ship.wav") ;
       
    return true;
}

//这里将碰撞监测，卷轴，陨石移动都放到一起了
void HelloWorld::update(float dt)
{
    CCPoint backgroundScrollVert = ccp(-1000,0);
    _backgroundNode->setPosition(ccpAdd(_backgroundNode->getPosition(), ccpMult(backgroundScrollVert,dt)));
    
    CCArray *spaceDusts = CCArray::arrayWithCapacity(2) ;
    spaceDusts->addObject(_spacedust1) ;
    spaceDusts->addObject(_spacedust2) ;
    
    for ( int ii = 0  ; ii <spaceDusts->count() ; ii++ ) {
        CCSprite * spaceDust = (CCSprite *)(spaceDusts->objectAtIndex(ii)) ;
        float xPosition = _backgroundNode->convertToWorldSpace(spaceDust->getPosition()).x  ;
        float size = spaceDust->getContentSize().width ;
        if ( xPosition < -size ) {
            //持续卷动空间尘埃
            _backgroundNode->incrementOffset(ccp(spaceDust->getContentSize().width*2,0),spaceDust) ;
        }
    }
    
    CCArray *backGrounds = CCArray::arrayWithCapacity(4) ;
    backGrounds->addObject(_galaxy) ;
    backGrounds->addObject(_planetsunrise) ;
    backGrounds->addObject(_spacialanomaly) ;
    backGrounds->addObject(_spacialanomaly2) ;
    
    for ( int ii = 0 ; ii <backGrounds->count() ; ii++ ) {
        CCSprite * background = (CCSprite *)(backGrounds->objectAtIndex(ii)) ;
        float xPosition = _backgroundNode->convertToWorldSpace(background->getPosition()).x ;
        float size = background->getContentSize().width ;
        if ( xPosition < -size ) {
            //持续卷动其他部分
            _backgroundNode->incrementOffset(ccp(2000,0),background) ; 
        }
    }
    
    
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    float maxY = winSize.height - _ship->getContentSize().height/2;
    float minY = _ship->getContentSize().height/2;
    
    float diff = (_shipPointsPerSecY * dt) ;
    float newY = _ship->getPosition().y + diff;
    newY = MIN(MAX(newY, minY), maxY);
    //飞船y轴变动。根据平衡感应重算后重画
    _ship->setPosition(ccp(_ship->getPosition().x, newY));
    
    float curTimeMillis = getTimeTick();
    //控制产生陨石随机间隔时间。注意此处没有用schedule_selector方式因为它不能控制随机出场
    if (curTimeMillis > _nextAsteroidSpawn) {
        float randMillisecs = randomValueBetween(0.2,1.0) * 1000;
        _nextAsteroidSpawn = randMillisecs + curTimeMillis;
        
        //陨石随机y轴位置
        //随机持续时间,即移动速度
        float randY = randomValueBetween(0.0,winSize.height);
        float randDuration = randomValueBetween(2.0,10.0);
        
        //产生陨石
        //_nextAsteroid默认为0. 是陨石数组的下标。
        CCSprite *asteroid = (CCSprite*)_asteroids->objectAtIndex(_nextAsteroid);
        _nextAsteroid++;
        
        //陨石数大于15，计数器归0
        if (_nextAsteroid >= _asteroids->count())
            _nextAsteroid = 0;
        
        asteroid->stopAllActions();
        asteroid->setPosition( ccp(winSize.width+asteroid->getContentSize().width/2, randY));
        asteroid->setVisible(true) ;
        //移动陨石
        asteroid->runAction ( CCSequence::actions(
                                                  CCMoveBy::actionWithDuration(randDuration,ccp(-winSize.width-asteroid->getContentSize().width,0)) ,
                                                   CCCallFuncN::actionWithTarget(this,callfuncN_selector(HelloWorld::setInvisible)) ,
                                                   NULL // DO NOT FORGET TO TERMINATE WITH NULL (unexpected in C++)
                                                   )
                             ) ;
    }

    //碰撞监测
    CCObject *itAster, *itLaser;
    CCARRAY_FOREACH(_asteroids, itAster)
    {
        CCSprite *asteroid = (CCSprite *)itAster;
        if ( !asteroid->isVisible())
            continue ;
        CCARRAY_FOREACH(_shipLasers, itLaser)
        {
            CCSprite *shipLaser = (CCSprite *)itLaser;
            if ( !shipLaser->isVisible() )
                continue ;
            //子弹击中陨石:爆炸
            if (CCRect::CCRectIntersectsRect(shipLaser->boundingBox(), asteroid->boundingBox()) ) {
                SimpleAudioEngine::sharedEngine()->playEffect("explosion_large.wav") ;
                shipLaser->setVisible(false) ;
                asteroid->setVisible(false) ;
                m_emitter = new CCParticleSystemQuad();
                m_emitter->initWithFile("ExplodingRing.plist");
                m_emitter->setTexture(CCTextureCache::sharedTextureCache()->addImage("explored.png"));
                this->addChild(m_emitter,10);
                m_emitter->setPosition(asteroid->getPosition());
                continue ;
            }
        }
        //飞船碰撞陨石:爆炸
        if ( CCRect::CCRectIntersectsRect(_ship->boundingBox(), asteroid->boundingBox()) ) {
            SimpleAudioEngine::sharedEngine()->playEffect("explosion_small.wav") ;
            asteroid->setVisible(false) ;
            _ship->runAction( CCBlink::actionWithDuration(1.0, 9)) ;
            _lives-- ;
        }
    }
    
    
    //输赢处理
    if ( _lives <= 0 ) {
        //Lose
        _ship->stopAllActions() ;
        _ship->setVisible(false) ;
        this->endScene(KENDREASONLOSE) ;
    } else if ( curTimeMillis >= _gameOverTime ) {
        this->endScene(KENDREASONWIN) ;
    }

}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
    CCDirector::sharedDirector()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

void HelloWorld::didAccelerate(CCAcceleration *pAccelerationValue)
{
#define KFILTERINGFACTOR .1
#define KRESTACCELX -.6
#define KSHIPMAXPOINTSPERSEC (winSize.height*.5)
#define KMAXDIFFX .2
    
    double rollingX;
    pAccelerationValue->x = pAccelerationValue->y ;
    rollingX = (pAccelerationValue->x * KFILTERINGFACTOR) + (rollingX * (1.0 - KFILTERINGFACTOR));
    float accelX = pAccelerationValue->x - rollingX ;
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    float accelDiff = accelX - KRESTACCELX;
    float accelFraction = accelDiff / KMAXDIFFX;
    //平衡感应重算y轴位置
    _shipPointsPerSecY = KSHIPMAXPOINTSPERSEC * accelFraction;
}

float HelloWorld::randomValueBetween( float low , float high ) {
    return (((float) arc4random() / 0xFFFFFFFFu) * (high - low)) + low;
}

float HelloWorld::getTimeTick() {
    timeval time;
    gettimeofday(&time, NULL);
    unsigned long millisecs = (time.tv_sec * 1000) + (time.tv_usec / 1000);
    return (float) millisecs;
}

void HelloWorld::setInvisible(CCNode * node) {
    node->setVisible(false) ;
}


//触摸事件: 发射导弹
void HelloWorld::ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event)
{
    SimpleAudioEngine::sharedEngine()->playEffect("laser_ship.wav") ;
    CCSize winSize = CCDirector::sharedDirector()->getWinSize() ;
    
    CCSprite *shipLaser = (CCSprite *)_shipLasers->objectAtIndex(_nextShipLaser++);
    if ( _nextShipLaser >= _shipLasers->count() )
        _nextShipLaser = 0;
    shipLaser->setPosition( ccpAdd( _ship->getPosition(), ccp(shipLaser->getContentSize().width/2, 0)));
    shipLaser->setVisible(true) ;
    shipLaser->stopAllActions() ;
    shipLaser->runAction( CCSequence::actions (
                                               CCMoveBy::actionWithDuration(0.5,ccp(winSize.width, 0)),
                                               CCCallFuncN::actionWithTarget(this,callfuncN_selector(HelloWorld::setInvisible)) ,
                                               NULL  // DO NOT FORGET TO TERMINATE WITH NULL 
                                               ) ) ; 
}

void HelloWorld::restartTapped() {
    CCDirector::sharedDirector()->replaceScene
    ( CCTransitionZoomFlipX::transitionWithDuration(0.5, this->scene()));
    // reschedule
    this->scheduleUpdate() ;
}

void HelloWorld::endScene( EndReason endReason ) {
    if ( _gameOver )
        return ;
    _gameOver = true ;
    
    CCSize winSize = CCDirector::sharedDirector()->getWinSize() ;
    char message[10] = "You Win"  ;
    if ( endReason == KENDREASONLOSE )
        strcpy(message,"You Lose") ;
    CCLabelBMFont * label ;
    label = CCLabelBMFont::labelWithString(message ,"Arial.fnt" );
    label->setScale(0.1) ;
    label->setPosition( ccp( winSize.width/2 , winSize.height*0.6)) ;
    this->addChild(label) ;
    
    CCLabelBMFont * restartLabel ;
    restartLabel = CCLabelBMFont::labelWithString("Restart" ,"Arial.fnt" );
    CCMenuItemLabel *restartItem = CCMenuItemLabel::itemWithLabel(restartLabel, this, menu_selector(HelloWorld::restartTapped) );
    restartItem->setScale(0.1) ;
    restartItem->setPosition( ccp( winSize.width/2 , winSize.height*0.4)) ;
    
    CCMenu *menu = CCMenu::menuWithItems(restartItem, NULL);
    menu->setPosition(CCPointZero);
    this->addChild(menu) ;
    
    // clear label and menu
    restartItem->runAction( CCScaleTo::actionWithDuration(0.5, 1.0)) ;
    label ->runAction( CCScaleTo::actionWithDuration(0.5, 1.0)) ;
    // Terminate update callback
    this->unscheduleUpdate() ;
}

